package com.prj.ufdm.webflux.config;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Set;

import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import com.prj.ufdm.webflux.annotation.ApiRouter;

@Component
public class HandlerBeanRegistry implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware{
	
	private ApplicationContext applicationContext;
	
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        /**
         * DESC: 获取 ApiRouter 注解的接口，这些接口就需要通过动态代理提供默认实现
         */
        Set<Class<?>> apiRouterlasses = getApiRouterClasses();
        System.out.println("\n 获取默认实现类：");
        System.out.println(apiRouterlasses);
        
        for (Class<?> apiRouterClass : apiRouterlasses) {
        	
        	System.out.println("\n apiRouterClass:"+apiRouterClass.getTypeName());
        	
            /**
             * 1. 获取继承自HandlerRouter的接口的泛型的类型typeName，传入到DynamicProxyBeanFactory
             * 2. 以便传入到DynamicProxyBeanFactory扫描typeName的实现类，然后按照feign和url两种实现方式分类
             */
            Type[] types = apiRouterClass.getGenericInterfaces();
            ParameterizedType type = (ParameterizedType) types[0];
            String className = type.getActualTypeArguments()[0].getTypeName();

            System.out.println("\n className:"+className);
            
            /**
             * DESC: 通过FactoryBean注入到spring容器，HandlerInterfaceFactoryBean实现以下功能：
             * 1.调用动态代理DynamicProxyBeanFactory提供HandlerRouter子接口的默认实现
             * 2.将第一步的默认实现，注入到spring容器
             */
            ApiRouter apiRouter = apiRouterClass.getAnnotation(ApiRouter.class);
            System.out.println("\n apiRouterClass.getName: "+apiRouterClass.getName());
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(apiRouterClass);
            GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
           
            System.out.println("\n definition.getPropertyValues():"+definition.getPropertyValues());
//            definition.getPropertyValues().add("interfaceClass", apiRouterClass);
            definition.getPropertyValues().add("className", className);
            definition.getPropertyValues().add("context", applicationContext);
            definition.setBeanClass(HandlerFactoryBean.class);
            definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
            
            System.out.println("\n 注入到Spring容器：");
            System.out.println("\n beanName:"+apiRouter.name());
            System.out.println("\n beanDefinition:"+definition);
            
            beanDefinitionRegistry.registerBeanDefinition(apiRouter.name(), definition);
            
           
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    	
    }

    /**
     * DESC: 通过反射扫描出所有使用ApiRouter的类
     * @return
     */
    private Set<Class<?>> getApiRouterClasses() {
        Reflections reflections = new Reflections(
                "com.prj.ufdm.webflux.*",
                new TypeAnnotationsScanner(),
                new SubTypesScanner()
        );
        return reflections.getTypesAnnotatedWith(ApiRouter.class);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * .通过class获取所有该类型的bean
     * @param <T>
     *
     * @param clazz
     * @return
     */
    private <T> Map<String, T> getBeans(Class<T> clazz) {
        return applicationContext.getBeansOfType(clazz);
    }

    private String getYmlProperty(String propery) {
        return applicationContext.getEnvironment().getProperty(propery);
    }
}
